package com.syq.face.utils;

import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.provider.DocumentsContract;
import android.provider.MediaStore;
import android.provider.OpenableColumns;
import android.util.Log;
import android.webkit.MimeTypeMap;

import androidx.annotation.RequiresApi;
import androidx.documentfile.provider.DocumentFile;

import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;

/**
 * @author ShangMeichun
 */
public class FileUtils {
    private static final String TAG = "FileUtils";


    public static byte[] File2byte(File tradeFile){
        byte[] buffer = null;
        try
        {
            FileInputStream fis = new FileInputStream(tradeFile);
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            byte[] b = new byte[1024];
            int n;
            while ((n = fis.read(b)) != -1)
            {
                bos.write(b, 0, n);
            }
            fis.close();
            bos.close();
            buffer = bos.toByteArray();
        }catch (FileNotFoundException e){
            e.printStackTrace();
        }catch (IOException e){
            e.printStackTrace();
        }
        return buffer;
    }

    public static Intent openCamera() {
        // 调起文件选择界面
        Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        return intent;
    }

    /**
     * 默认不进行任何筛选
     *
     * @return intent
     */
    public static Intent openDocumentPicker() {
        // 调起文件选择界面
        Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
        //筛选，只显示可以“打开”的结果，如文件(而不是联系人或时区列表)
        intent.addCategory(Intent.CATEGORY_OPENABLE);
        intent.setType("*/*");
        return intent;
    }

    /**
     * 筛选指定mimeType类型的文件
     *
     * @param mimeType 传入的mimeType作为筛选条件
     * @return intent
     */
    public static Intent openDocumentPicker(String mimeType) {
        // 调起文件选择界面
        Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
        //筛选，只显示可以“打开”的结果，如文件(而不是联系人或时区列表)
        intent.addCategory(Intent.CATEGORY_OPENABLE);
        intent.setType(mimeType);
        return intent;
    }

    @RequiresApi(api = Build.VERSION_CODES.Q)
    public static File uriToFileApiQ(Uri uri, Context context) {
        File file = null;
        if (uri == null) {
            return null;
        }
        //android10以上转换
        if (uri.getScheme().equals(ContentResolver.SCHEME_FILE)) {
            file = new File(uri.getPath());
        } else if (uri.getScheme().equals(ContentResolver.SCHEME_CONTENT)) {
            //把文件复制到沙盒目录
            ContentResolver contentResolver = context.getContentResolver();
            String displayName = System.currentTimeMillis() + Math.round((Math.random() + 1) * 1000)
                    + "." + MimeTypeMap.getSingleton().getExtensionFromMimeType(contentResolver.getType(uri));

            try {
                InputStream is = contentResolver.openInputStream(uri);
                File cache = new File(context.getExternalCacheDir().getAbsolutePath(), displayName);
                FileOutputStream fos = new FileOutputStream(cache);
                android.os.FileUtils.copy(is, fos);
                file = cache;
                fos.close();
                is.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return file;
    }

    /**
     * 传入文件名，不需要传入后缀，会自动根据原本文件的后缀生成新的文件的后缀
     * 如果传入的文件名为null，文件名将以系统当前时间的微秒数
     * 兼容各个版本
     *
     * @param context  上下文对象
     * @param uri      要生成的文件的uri
     * @param filename 可为null, 为null则以当前微秒数作为名称
     * @return 生成的文件
     */
    public static File uriToFile(Context context, Uri uri, String filename) {
        DocumentFile documentFile = DocumentFile.fromSingleUri(context, uri);
        String fileExtension = getFileExtension(documentFile.getName());
        if (filename == null) {
            filename = System.currentTimeMillis() + "";
        }
        //分支处理各个版本的情况，以后有新的版本就多一条分支语句，else语句中处理4.4及以下的版本
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            return uriToFileForQ(context, uri, "temp", filename, fileExtension);
        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            return uriToFileForN(context, uri, filename, fileExtension);
        } else {
            return uriToFileForKitkat(context, uri, filename, fileExtension);
        }
    }

    /**
     * 获取文件的扩展名（即后缀）
     * 如果文件没有扩展名，那么返回整个文件的名称
     *
     * @param filename 完整的文件名
     * @return 文件的后缀
     */
    public static String getFileExtension(String filename) {
        int index = filename.indexOf('.');
        if (index == -1) {
            return filename;
        } else {
            return filename.substring(index);
        }
    }

    /**
     * android 7使用，获取文件
     *
     * @param context       上下文对象
     * @param uri           文件的uri
     * @param filename      文件名（不包含后缀）
     * @param fileExtension 文件后缀
     * @return 根据uri的内容重新生成一个文件
     */
    private static File uriToFileForN(Context context, Uri uri, String filename, String fileExtension) {
        File file = new File(context.getFilesDir(), filename + fileExtension);
        try (FileOutputStream outputStream = new FileOutputStream(file);
             InputStream inputStream = context.getContentResolver().openInputStream(uri)) {
            Log.d(TAG, "uriToFileForN: context.getFilesDir:" + context.getFilesDir());
            //复制文件
            int read = 0;
            int maxBufferSize = 1024 * 1024;
            int bytesAvailable = inputStream.available();
            int bufferSize = Math.min(bytesAvailable, maxBufferSize);
            final byte[] buffers = new byte[bufferSize];
            while ((read = inputStream.read(buffers)) != -1) {
                outputStream.write(buffers, 0, read);
            }
            Log.d(TAG, "uriToFileForN: file:" + file.getAbsolutePath());
            Log.d(TAG, "uriToFileForN: file:" + file);
            return file;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


    /**
     * 将uri转化为file 适用于android4.4及以下
     *
     * @param context       上下文对象
     * @param uri           文件的uri
     * @param filename      文件名（不包括后缀）
     * @param fileExtension 文件后缀
     * @return 转化的file（为null说明转化失败）
     */
    public static File uriToFileForKitkat(Context context, Uri uri, String filename, String fileExtension) {
        String path = uriToFilePathForKitkat(context, uri);
        //路径为null需要检查上面的方法
        if (path == null) {
            Log.d(TAG, "uriToFileForKitkat: 路径为null");
            return null;
        }
        File oldFile = new File(path);
        Log.d(TAG, "uriToFileForKitkat: path:" + path);
        Log.d(TAG, "uriToFileForKitkat: filepath:" + oldFile.getAbsolutePath());
        Log.d(TAG, "uriToFileForKitkat: filename:" + oldFile.getName());
        int index = path.lastIndexOf("/");
        String newName = filename + fileExtension;
        //获取要改名的新文件
        File newFile = new File(path.substring(0, index) + "/" + newName);
        //如果要改名的文件已经存在,那么删除
        if (newFile.exists()) {
            newFile.delete();
        }
        boolean isRenamed = oldFile.renameTo(newFile);
        if (isRenamed) {
            return newFile;
        } else {
            //如果重命名失败，那么返回null
            return null;
        }
    }

    /**
     * android 7.0 以下的处理方法
     * 包含4.4的处理方法以及4.4版本以下的处理方法
     * 获取文件路径
     *
     * @param context 上下文对象
     * @param uri     文件的uri
     * @return 文件的path
     */
    public static String uriToFilePathForKitkat(Context context, Uri uri) {
        final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
        // android 4.4 以上， android 7以下 -- DocumentProvider进行封装过
        if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
            Log.d(TAG, "getFilePathBeforeAndroidQ: 安卓版本4.4且为");
            // ExternalStorageProvider
            if (isExternalStorageDocument(uri)) {
                final String docId = DocumentsContract.getDocumentId(uri);
                final String[] split = docId.split(":");
                final String type = split[0];
                //判断是否私有
                if ("primary".equalsIgnoreCase(type)) {
                    return Environment.getExternalStorageState() + "/" + split[1];
                }
            }
            // DownloadsProvider
            else if (isDownloadsDocument(uri)) {

                final String id = DocumentsContract.getDocumentId(uri);
                final Uri contentUri = ContentUris.withAppendedId(
                        Uri.parse("content://downloads/public_downloads"), Long.parseLong(id));
                return getDataColumn(context, contentUri, null, null);
            }
            // MediaProvider
            else if (isMediaDocument(uri)) {
                final String docId = DocumentsContract.getDocumentId(uri);
                final String[] split = docId.split(":");
                final String type = split[0];

                Uri contentUri = null;
                if ("image".equals(type)) {
                    contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
                } else if ("video".equals(type)) {
                    contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
                } else if ("audio".equals(type)) {
                    contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
                }

                final String selection = "_id=?";
                final String[] selectionArgs = new String[]{
                        split[1]
                };
                return getDataColumn(context, contentUri, selection, selectionArgs);
            }
        }
        // MediaStore (and general)
        else if ("content".equalsIgnoreCase(uri.getScheme())) {
            Log.d(TAG, "getFilePathBeforeAndroidQ: MediaStore");
            return getDataColumn(context, uri, null, null);
        }
        // File
        else if ("file".equalsIgnoreCase(uri.getScheme())) {
            Log.d(TAG, "getFilePathBeforeAndroidQ: file");
            return uri.getPath();
        }

        return null;
    }

    /**
     * 将uri对应的文件复制到外部私有目录下
     * 直接指定文件名以及后缀
     *
     * @param context           上下文对象
     * @param uri               要复制的文件
     * @param fileDirectoryName 文件要复制到的私有目录,格式为xxx/xxx/... 如temp, temp/avatar, ...
     * @param fileName          文件名
     * @param fileExtension     文件名的后缀
     * @return 复制后的文件
     */
    @RequiresApi(api = Build.VERSION_CODES.Q)
    public static File uriToFileForQ(Context context, Uri uri, String fileDirectoryName, String fileName, String fileExtension) {
        String path = context.getExternalFilesDir(fileDirectoryName).getAbsolutePath();
        File tempFile = new File(path, fileName + fileExtension);
        try (InputStream inputStream = context.getContentResolver().openInputStream(uri);
             OutputStream outputStream = new FileOutputStream(tempFile)) {
            android.os.FileUtils.copy(inputStream, outputStream);
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
        return tempFile;
    }

    /**
     * 通过MediaStore 可以查询其他程序创建的多媒体文件，而不能查询其他程序创建的非媒体文件
     *
     * @return 返回查询到的文件的uri
     */
    @RequiresApi(api = Build.VERSION_CODES.Q)
    public static Uri selectFile(Context context) {
        Uri queryUri = null;
        //  这个uri代表的是查询全部文件
        Uri externalUri = MediaStore.Files.getContentUri("external");
        // 这个uri代表的获得download文件下的文件, 需要android 10
        //Uri downloadUri = MediaStore.Downloads.EXTERNAL_CONTENT_URI;
        // projection 用来获取要查询的指定的文件字段, 是第二个参数, 这里是查询了id，MIME_TYPE文件类型，size大小，DATE_MODIFIED修改日期,DISPLAY_NAME 文件名
        String[] projection = new String[]{MediaStore.Files.FileColumns._ID, MediaStore.Files.FileColumns.MIME_TYPE, MediaStore.Files.FileColumns
                .SIZE, MediaStore.Files.FileColumns.DATA, MediaStore.Files.FileColumns.DISPLAY_NAME};
        // selection 是用来确定查询的条件, 被注释掉的是查询该目录的下级目录下的文件，BUCKET_DISPLAY_NAME就是下级目录的名字
        String selection = MediaStore.Files.FileColumns.MIME_TYPE + "=?";
        //String selection = MediaStore.Files.FileColumns.BUCKET_DISPLAY_NAME + "=?";
        String selectionArgs = "text/plain";
        // 这个cursor是指定了查询的条件以及参数
        Cursor cursor = context.getContentResolver().query(externalUri, projection, null, null, null);
        if (cursor != null && cursor.moveToFirst()) {
            while (!cursor.isAfterLast()) {
                //获取uri
                //queryUri = ContentUris.withAppendedId(externalUri, cursor.getColumnIndexOrThrow(MediaStore.Files.FileColumns._ID));
                queryUri = externalUri.buildUpon().appendPath(String.valueOf(cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Files.FileColumns._ID)))).build();
                //获取filename
                String filename = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Files.FileColumns.DATA));
                Log.d(TAG, "selectFile.filename: " + filename + "\nuri: " + queryUri);
                cursor.moveToNext();
            }
            cursor.close();
        }

        return queryUri;
    }

    /**
     * Android10 在Download文件夹下根据filename和mimeType来创建文件
     *
     * @param context  传入activity的context
     * @param filename 创建的文件的名称
     * @param mimeType 创建的文件的mimeType类型
     * @return 创建的文件的uri
     */
    @RequiresApi(api = Build.VERSION_CODES.Q)
    public static Uri createFileInDownload(Context context, String filename, String mimeType) {
        // android 10创建文件
        ContentResolver contentResolver = context.getContentResolver();
        //设置文件参数到values中
        ContentValues contentValues = new ContentValues();
        //设置文件名
        contentValues.put(MediaStore.Downloads.DISPLAY_NAME, filename);
        //设置mimeType，这里的是xlsx
        contentValues.put(MediaStore.Downloads.MIME_TYPE, mimeType);
        return contentResolver.insert(MediaStore.Downloads.EXTERNAL_CONTENT_URI, contentValues);
    }


    private static String getFilePathForAndroidN(Context context, Uri uri) {
        try (Cursor cursor = context.getContentResolver().query(uri, null, null, null, null);
             InputStream inputStream = context.getContentResolver().openInputStream(uri)) {

            int nameIndex = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
            cursor.moveToFirst();
            String name = (cursor.getString(nameIndex));
            Log.d(TAG, "getFilePathForAndroidN: :" + context.getFilesDir());
            File file = new File(context.getFilesDir(), name);

            FileOutputStream outputStream = new FileOutputStream(file);
            int read = 0;
            int maxBufferSize = 1024 * 1024;
            int bytesAvailable = inputStream.available();

            int bufferSize = Math.min(bytesAvailable, maxBufferSize);

            final byte[] buffers = new byte[bufferSize];
            while ((read = inputStream.read(buffers)) != -1) {
                outputStream.write(buffers, 0, read);
            }
            outputStream.close();
            Log.d(TAG, "getFilePathForAndroidN: file:" + file.getAbsolutePath());
            Log.d(TAG, "getFilePathForAndroidN: file:" + file);
            return file.getPath();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * android 10 以下的处理方法
     */
    public static String getFilePathBeforeAndroidQ(final Context context, final Uri uri) throws Exception {

        final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
        final boolean isN = Build.VERSION.SDK_INT >= Build.VERSION_CODES.N;

        //android 7 以上， android 10以下
        if (isN) {
            Log.d(TAG, "getFilePathBeforeAndroidQ: android版本7");
            return getFilePathForAndroidN(context, uri);
        }

        // android 4.4 以上， android 7以下 -- DocumentProvider进行封装过
        if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
            Log.d(TAG, "getFilePathBeforeAndroidQ: 安卓版本4.4且为");
            // ExternalStorageProvider
            if (isExternalStorageDocument(uri)) {
                final String docId = DocumentsContract.getDocumentId(uri);
                final String[] split = docId.split(":");
                final String type = split[0];
                //判断是否私有
                if ("primary".equalsIgnoreCase(type)) {
                    return Environment.getExternalStorageState() + "/" + split[1];
                }

            }
            // DownloadsProvider
            else if (isDownloadsDocument(uri)) {

                final String id = DocumentsContract.getDocumentId(uri);
                final Uri contentUri = ContentUris.withAppendedId(
                        Uri.parse("content://downloads/public_downloads"), Long.parseLong(id));
                return getDataColumn(context, contentUri, null, null);
            }
            // MediaProvider
            else if (isMediaDocument(uri)) {
                final String docId = DocumentsContract.getDocumentId(uri);
                final String[] split = docId.split(":");
                final String type = split[0];

                Uri contentUri = null;
                if ("image".equals(type)) {
                    contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
                } else if ("video".equals(type)) {
                    contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
                } else if ("audio".equals(type)) {
                    contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
                }

                final String selection = "_id=?";
                final String[] selectionArgs = new String[]{
                        split[1]
                };
                return getDataColumn(context, contentUri, selection, selectionArgs);
            }
        }
        // MediaStore (and general)
        else if ("content".equalsIgnoreCase(uri.getScheme())) {
            Log.d(TAG, "getFilePathBeforeAndroidQ: MediaStore");
            return getDataColumn(context, uri, null, null);
        }
        // File
        else if ("file".equalsIgnoreCase(uri.getScheme())) {
            Log.d(TAG, "getFilePathBeforeAndroidQ: file");
            return uri.getPath();
        }

        return null;
    }

    /**
     * 获取此Uri的数据列的值。这对于MediaStore uri和其他基于文件的内容提供程序非常有用。
     * android 10 以下可以使用， 以上则废弃。
     */
    public static String getDataColumn(Context context, Uri uri, String selection,
                                       String[] selectionArgs) {
        final String[] projection = {MediaStore.Images.ImageColumns.DATA};
        try (Cursor cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null)) {
            if (cursor != null && cursor.moveToFirst()) {
                final int columnIndex = cursor.getColumnIndexOrThrow(MediaStore.Images.ImageColumns.DATA);
                return cursor.getString(columnIndex);
            }
        } catch (IllegalArgumentException e) {
            //do nothing
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 判断是否是外部存储文件
     * 包含共有目录和私有目录
     *
     * @param uri
     * @return
     */
    public static boolean isExternalStorageDocument(Uri uri) {
        return "com.android.externalstorage.documents".equals(uri.getAuthority());
    }

    /**
     * 判断是否是Downloads目录的文件
     *
     * @param uri
     * @return
     */
    public static boolean isDownloadsDocument(Uri uri) {
        return "com.android.providers.downloads.documents".equals(uri.getAuthority());
    }

    /**
     * 判断是否是media文件
     *
     * @param uri
     * @return
     */
    public static boolean isMediaDocument(Uri uri) {
        return "com.android.providers.media.documents".equals(uri.getAuthority());
    }


}
